# https://www.bilibili.com/video/BV1c4411e77t?spm_id_from=333.788.player.switch&vd_source=c63dc52d041e128bfe6493a856498ed4&p=73

# class property(fget=None, fset=None, fdel=None, doc=None)
# 虽然我们习惯叫他“函数”，但其实gen int(),str(),float()函数一样，是一个"Build-in Class"

# 1.用于返回一个 property 属性对象
class C:

    def __init__(self):
        self._x = 250

    def getx(self):
        return self._x

    def setx(self, value):
        self._x = value

    def delx(self):
        del self._x

    # 将上面的3个函数作为参数传入 property 函数，并且赋值给x
    x = property(getx, setx, delx)


print("================================================================================" * 3)

c = C()
print(c.x)
# 250

print("================================================================================" * 3)
c.x = 520
print(c.__dict__)
# {'_x': 520}

del c.x
print(c.__dict__)


# {}

# 由上可知，这个 property 跟 __setattr__,__getattr__,delattr__不是重复了吗？为什么要重复造轮子呢？

class D:

    def __init__(self):
        self._x = 250

    def __getattr__(self, name):
        if name == 'x':
            return self._x
        else:
            return super().__getattr__(name)

    def __setattr__(self, name, value):
        if name == 'x':
            super().__setattr__('_x', value)
        else:
            super().__setattr__(name, value)

    def __delattr__(self, name):
        if name == 'x':
            super().__delattr__('_x')
        else:
            super().__delattr__(name)


d = D()
print(d.x)
# 250
d.x = 520
print(d.__dict__)
# {'_x': 520}
del d.x
print(d.__dict__)
# {}

# 由此可见，使用上面的方法太复杂了，还是 property 函数好用
print("================================================================================" * 3)


class E:

    def __init__(self):
        self._x = 250

    # 把 property 函数当作装饰器去用，实现上面的功能就更简单了
    # 这是一个只读的属性 x
    @property
    def x(self):
        return self._x


e = E()
print(e.x)
# 250

# 因为由 property 装饰的是一个只读属性，不能写，下面会报错
# e.x = 520
# AttributeError: can't set attribute

print("================================================================================" * 3)


class F:

    def __init__(self):
        self._x = 250

    def x(self):
        return self._x

    # 用下面的方法也能创建一个只读属性 x
    x = property(x)


f = F()
print(f.x)
# 250

# 因为由 property 装饰的是一个只读属性，不能写，下面会报错
# f.x = 520
# AttributeError: can't set attribute


print("================================================================================" * 3)


class G:

    def __init__(self):
        self._x = 250

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x


g = G()
print(g.x)
# 250

g.x = 520
print(g.__dict__)
# {'_x': 520}
del g.x
print(g.__dict__)
# {}
